/**
 * 
 */
package com.huniu.links.colony;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.util.SimpleNodeIterator;

import com.huniu.links.exception.LinkProcessException;
import com.huniu.links.model.LinkXMLProperty;
import com.huniu.links.model.SeedXMLProperty;
import com.huniu.utility.DateUtil;

/**
 * @author zandy (chenheng)
 * 
 */
public class LeaderBeeBehaviorImpl extends AbstractBeeBehaviorImpl implements
		ILeaderBeeBehavior {

	private static Logger logger = Logger
			.getLogger(LeaderBeeBehaviorImpl.class);

	private File linkFile;
	private String seedFolder ;

	public void setLinkFile(File linkFile) {
		this.linkFile = linkFile;
	}

	public void setSeedFolder(String seedFolder) {
		this.seedFolder = seedFolder;
	}

	private String getCacheContent(String url) throws LinkProcessException {
		logger.info("=============================>>>> Begin to get content form Cache");
		CacheManager singletonManager = CacheManager.create();
		logger.info("Get singleton cache manager : "
				+ singletonManager.getName());
		Cache cache = singletonManager.getCache(LINK_PAGE_CACHE_NAME);
		logger.info("Get cache object : " + cache.getName());
		Element element = cache.get(url);
		if ( element == null ) {
			throw new LinkProcessException("Hit url failure : " + url,null);
		}
		String content = (String) element.getValue();
		logger.info("Get emement({key=" + url + ",value=...}) from cache : "
				+ cache.getName());
		logger.info("<<<<============================= Finish to get content form Cache");
		return content;
	}

	private NodeList gatherLinks(String url) throws ParserException, LinkProcessException {
		String content = getCacheContent(url);
		logger.info("=============================>>>> Begin to parser html");
		Parser parser = Parser.createParser(content, CHARSET);
		logger.info("Create parser : " + parser.getEncoding());
		NodeFilter nodeFilter = new NodeClassFilter(LinkTag.class);
		HasAttributeFilter attrFilter = new HasAttributeFilter("href");
		AndFilter andFilter = new AndFilter(nodeFilter,attrFilter);
		logger.info("Set Node Filter to filer Link Tag");
		NodeList nodeList = parser.extractAllNodesThatMatch(andFilter);
		logger.info("Fetch Link Tag Node List");
		logger.info("<<<<============================= Finish to parser html");
		return nodeList ;
		
	}
	private Document generateSeedDocument(NodeList nodeList) {
		Document seedDocument = DocumentHelper.createDocument();
		org.dom4j.Element root = seedDocument.addElement(SeedXMLProperty.ROOT);
		SimpleNodeIterator iterator = nodeList.elements(); 
		while ( iterator.hasMoreNodes()) {
			Node node = iterator.nextNode();
			String[] items = node.getText().split("\\s");
			for (String item : items) {
				if ( item.startsWith("href")) {
					item = item.substring(item.indexOf("href=") + 5).replace("\"", "");
					if ( ! item.trim().matches("\\s") && ! item.trim().equals("")) {
						root.addElement(SeedXMLProperty.ELEMENT).addText(item);
					}
				}
			}
		}
		return seedDocument ;
	}
	
	private void generateSeedFile(Document document) throws LinkProcessException {
		String fileName = DateUtil.convertDateToString(new Date(),
				DateUtil.DATE_FORMAT_2);
		String filePath = this.seedFolder + File.separator + fileName + LinkXMLProperty.EXTENSION;
		try {
			OutputFormat format = OutputFormat.createPrettyPrint();
			XMLWriter writer = new XMLWriter(
					new FileWriter(new File(filePath)), format);
			writer.write(document);
			writer.close();
		} catch (IOException e) {
			throw new LinkProcessException("Write XML document failure", e);
		}
	}

	public void process() {
		try {
			Document document = parseXMLFile(linkFile);
			List<String> urlList = this.parseLinks(document,
					LinkXMLProperty.ELEMENT);
			for (String url : urlList) {
				NodeList nodeList = gatherLinks(url);
				if ( nodeList != null && nodeList.size() > 0 ) {
					Document seedDocument = generateSeedDocument(nodeList);
					generateSeedFile(seedDocument);
				}
			}
		} catch (DocumentException e) {
			logger.error(e.getMessage(), e);
		} catch (LinkProcessException e) {
			logger.error(e.getMessage(), e);
		} catch (ParserException e) {
			logger.error(e.getMessage(), e);
		}
	}

	public void run() {
		process();
	}
}
